<template>
  <!-- 自定义表单 -->
  <a-row type="flex">
    <template v-for="(item, index) in formList">
      <!-- <transition :key="item.keyName" name="fade-bottom" mode="out-in"> -->
      <title-name
        v-if="item.title"
        :key="index"
        :title="item.title"
        style="width: 100%"
      />
      <a-col
        v-else-if="!item.hidden"
        :key="item.keyName"
        :span="item.span || 8"
        :class="item.formClass || ''"
      >
        <!-- 自定义表单项容器 -->
        <template v-if="item.customItemSlot">
          <slot :name="item.keyName" />
        </template>
        <template v-else-if="item.type == 'orgTree'">
          <!--          <slot :name="item.keyName" />-->
          <a-form-model-item :colon="item.colon" :label="item.label" :prop="item.keyName">
<!--                        {{form}} {{item.keyName}}-->
            <org-tree-select
                    v-if="!item.isNoBorder"
                    v-model="form[item.keyName]"
                    v-bind="item"
                    @getProjectInfo="getProjectInfo"
            @select="selectOrg"></org-tree-select>
            <span v-else class="text_name">{{ form[item.viewName] }}</span>
          </a-form-model-item>
        </template>
<!--        为了不影响他们写的不严谨的代码 我自己在复制一份 需要什么配置自己传-->
        <template v-else-if="item.type == 'ATreeSelect'">
          <a-form-model-item :colon="item.colon" :label="item.label" :prop="item.keyName">
            <a-tree-select :disabled="item.disabled" :multiple="item.multiple" v-model="form[item.keyName]"
                           placeholder="请选择"
                           :tree-data="item.data"
                           allow-clear
                           v-on="listeners(item)"
                           v-bind="getAttrs(item)" >
                           <a-spin v-if="item.loading" slot="notFoundContent" size="small" />
                           <a-icon v-if="item.loading" style="color: #096dd9" slot="suffixIcon" type="loading" />
                          </a-tree-select>
          </a-form-model-item>
        </template>
        <template v-else-if="item.type == 'a-tree-Select'">
          <a-form-model-item :colon="item.colon" :label="item.label" :prop="item.keyName">
            <a-tree-select :disabled="item.disabled" :multiple="item.multiple" v-model="form[item.keyName]" show-search
                           :replaceFields="{ children: 'children', title: 'name', key: 'id', value: 'id' }" placeholder="请选择"
                           :tree-data="item.data" allow-clear v-bind="getAttrs(item)" />
          </a-form-model-item>
        </template>
        <!-- ant-form-item--full 当item.label === '' 空时label不显示，表单内容独占宽度 -->
        <a-form-model-item
          v-else
          v-bind="getProp(item)"
          :colon="item.colon"
          :label="item.label"
          :class="{'ant-form-item--full':item.label==='', 'requiredFormItem': item.required}"
        >
          <!-- 插槽 -->
          <slot
            v-if="item.slot"
            :name="item.keyName"
            :data="{ value: form[item.keyName], formItem: item, form }"
          />
          <template v-else>
            <!-- 自定义表单项 -->
            <component
              :is="item.type"
              v-if="(editModel !== 'V' && item.type !== 'uploadFile' && item.type !== 'SelectPerson') || item.isEdit"
              v-model="form[item.keyName]"
              v-bind="getAttrs(item)"
              :disabled="item.disabled"
              :form="form"
              :precision="item.precision"
              style="width:100%"
              :placeholder="item.placeholder || getPlaceholder(item)"
              :auto-size="item.autoSize"
              v-on="listeners(item)"
              @openChange="(e) => (item.isopen = e)"
              @panelChange="(value) => panelChange(item.keyName, value)"
              @getPostInfo="getPostInfo"
            >
              <!-- 若为非组件手写选择器 -->
              <template v-if="item.type == 'a-select' && !item.typeGroup">
                <a-select-option
                  v-for="i in item.data"
                  :key="i[Object.keys(item.replaceFields || {}).length > 0 ? item.replaceFields.value : 'value']"
                  :value="i[Object.keys(item.replaceFields || {}).length > 0 ? item.replaceFields.value : 'value']"
                >
                  {{ i[Object.keys(item.replaceFields || {}).length > 0 ? item.replaceFields.label : 'label'] }}
                </a-select-option>
              </template>
              <!-- 若为非组件手写选择器 用 OptGroup 进行选项分组 -->
              <template v-if="item.type == 'a-select' && item.typeGroup == 'a-select-opt-group'">
                <a-select-opt-group
                  v-for="(i, index) in item.data"
                  :key="index"
                >
                  <span slot="label">
                    <a-icon type="user" />{{ i[Object.keys(item.replaceFields || {}).length > 0 ? item.replaceFields.label : 'label'] }}
                  </span>
                  <a-select-option
                    v-for="j in i[Object.keys(item.replaceFields || {}).length > 0 ? item.replaceFields.childOpt : 'childOpt']"
                    :key="item.customRender(i, j) || j[Object.keys(item.replaceFields || {}).length > 0 ? item.replaceFields.childValue : 'value']"
                    :value="item.customRender(i, j) || j[Object.keys(item.replaceFields || {}).length > 0 ? item.replaceFields.childValue : 'value']"
                  >
                    {{ item.customRenderLabel(i, j) || j[Object.keys(item.replaceFields || {}).length > 0 ? item.replaceFields.childrenLabel : 'label'] }}
                  </a-select-option>
                </a-select-opt-group>
              </template>
              <!-- 若为非组件手写单选框 -->
              <template v-if="item.type == 'a-radio-group'">
                <a-radio
                  v-for="i in item.data"
                  :key="i[Object.keys(item.replaceFields || {}).length > 0 ? item.replaceFields.value : 'value']"
                  :value="i[Object.keys(item.replaceFields || {}).length > 0 ? item.replaceFields.value : 'value']"
                >
                  {{ i[Object.keys(item.replaceFields || {}).length > 0 ? item.replaceFields.label : 'label'] }}
                </a-radio>
              </template>
            </component>
            <!-- 文件上传 -->
            <template v-if="item.type === 'uploadFile'">
              <template v-if="(editModel != 'V' && !item.disabled) || (item.attrs && item.attrs.uploadType === 'image')">
                <l-table
                  v-bind="item.attrs"
                  :business-code="item.businessCode"
                  :upload-arrys.sync="form[item.keyName]"
                  @fileArrysData="handleFileChange(item.keyName)"
                />
                <div
                  v-if="!item.hiddenPrompt && item.attrs && item.attrs.uploadType !== 'image'"
                  class="file_prompt"
                >
                  {{ item.remark || '请上传原件，支持格式：.rar .zip .doc .docx .pdf .jpg .png .mp4 .mov' }}
                </div>
                <!-- 备注 -->
                <div
                  v-if="item.hiddenRemark"
                  class="file_prompt"
                >
                  {{ item.remark || '请上传原件，支持格式：.rar .zip .doc .docx .pdf .jpg .png .mp4 .mov' }}
                </div>
              </template>
              <file-link
                v-else
                :file-list="form[item.keyName]"
              />
            </template>
            <!-- 人员选择（弹窗） -->
            <template v-if="item.type === 'SelectPerson'">
              <div style="margin-top: -3px">
                <!-- 人员列表 -->
                <template v-if="item.isInput">
                  <a-row
                    type="flex"
                    justify="space-between"
                    align="middle"
                    style="flex-wrap: nowrap"
                  >
                    <ellipsis
                      v-if="editModel === 'V'"
                      tooltip
                      :length="Number(item.span || 8) * 4.5"
                    >
                      <!-- 可格式化填充内容，customRender为格式化 -->
                      {{
                        formatPerson(item) && formatPerson(item).length
                          ? formatPerson(item)
                              .map((i) => i.name)
                              .join('，')
                          : '无'
                      }}
                    </ellipsis>
                    <BaseInput
                      v-else
                      style="width: 100%"
                      :value="
                        formatPerson(item) && formatPerson(item).length
                          ? formatPerson(item)
                              .map((i) => i.name)
                              .join('，')
                          : void 0
                      "
                      @change="handleFileChange(item.keyName)"
                      disabled
                    ></BaseInput>
                    <!-- 新增按钮 -->
                    <a-button
                      v-if="editModel !== 'V'"
                      class="ml12"
                      style="flex-shrink: 0"
                      icon="plus"
                      size="small"
                      type="primary"
                      :disabled="item.disabled"
                      ghost
                      v-bind="item.btnAttrs"
                      @click="!item.isSingle ? handleOpen(item.keyName) : (visible = true)"
                    >
                      新增
                    </a-button>
                  </a-row>
                </template>
                <template v-else>
                  <a-tag
                    v-for="(person, index) in formatPerson(item)"
                    :key="person[item.idField || 'userId']"
                    class="mb10"
                    :closable="item.disabled === false || editModel !== 'V'"
                    color="#108ee9"
                    @close="handleRemove(index, item)"
                  >
                    {{ person.name }}
                  </a-tag>
                  <!-- 新增按钮 -->
                  <a-button
                    v-if="editModel !== 'V'"
                    class="ml12"
                    style="flex-shrink: 0"
                    icon="plus"
                    size="small"
                    type="primary"
                    :disabled="item.disabled"
                    ghost
                    v-bind="item.btnAttrs"
                    @click="!item.isSingle ? handleOpen(item.keyName) : (visible = true)"
                  >
                    新增
                  </a-button>
                </template>
              </div>
              <!-- 单选人员 -->
              <SelectPersonModal
                v-if="item.isSingle"
                v-bind="item.attrs"
                :personsList="formatPerson(item)"
                :visible.sync="visible"
                v-on="listeners(item)"
                @confirmSelect="(e) => handleAdd(e, item)"
              />
              <!-- 复选人员 -->
              <SelectPerson
                v-else
                :ref="'dialogEdit' + item.keyName"
                v-bind="item.attrs"
                :header-title="item.headerTitle || '添加人员'"
                :form="item.formAttrs || { whether: false }"
                :selectData="item.isEcho ? formatPerson(item) : []"
                :keyName="item.idField"
                :checkStrictly="true"
                v-on="listeners(item)"
                @confirm="(e) => handleAdd(e, item)"
              />
            </template>
            <!-- 操作为查看时 -->
            <template v-else-if="!item.isEdit && editModel === 'V' && item.type !== 'uploadFile'">
              <ellipsis
                v-if="item.type !== 'BaseTextarea' && item.type !== 'baseTextarea' && item.type !== 'base-textarea' && item.type !== 'Base-textarea'"
                tooltip
                :length="Number(item.span || 8) * (item.maxLength || 4.5)"
                class="text_name"
              >
                <!-- 可格式化填充内容，customRender为格式化 -->
                {{
                  item.customRender
                    ? item.customRender(form[item.viewName || item.keyName], form)
                    : form[item.viewName || item.keyName] || form[item.viewName || item.keyName] == 0
                    ? form[item.viewName || item.keyName]
                    : '无'
                }}
              </ellipsis>
              <div
                v-else
                class="text_name"
              >
                <!-- 可格式化填充内容，customRender为格式化 -->
                {{
                  item.customRender
                    ? item.customRender(form[item.viewName || item.keyName], form)
                    : form[item.viewName || item.keyName] || form[item.viewName || item.keyName] == 0
                    ? form[item.viewName || item.keyName]
                    : '无'
                }}
              </div>
            </template>
          </template>
        </a-form-model-item>
      </a-col>
      <div
        v-if="item.wrap"
        :key="index"
        style="width: 100%"
      />
      <!-- </transition> -->
    </template>
  </a-row>
</template>

<script>
import { Ellipsis } from '@/components'
import { getAuditProject } from '@/api/themeChoose/themeChoose' // 表格

export default {
  name: 'BaseForm',
  inheritAttrs: false,
  components: {
    Ellipsis,
    SelectPerson: () => import('@/components/BComponents/BSelectPerson'),
    SelectPersonModal: () => import('@/components/SelectPersonModal')
  },
  props: {
    // 表单
    form: {
      type: Object,
      default: () => null
    },
    // 表单组件列表
    formList: {
      type: Array
    },
    // 操作类型:V为查看，其他操作类型自定义
    editModel: {
      type: String,
      default: () => 'V'
    },
    // 表单事件是否使用自定义事件，为false直接在formList回调
    isEmit: {
      type: Boolean,
      default: () => true
    },
    // 外部表单名
    formName: {
      type: String,
      default: () => 'ruleForm'
    },
    // 外部表单
    formComponents: {
      type: [Object],
      default: () => null
    }
  },
  data() {
    return {
      personList: [], // 人员列表
      visible: false, // 人员弹窗显隐控件
      defaultPlaceholder: {
        请输入: ['a-input', 'a-input-search', 'BaseInput', 'BaseTextarea', 'a-input-number', 'BaseInputNumber'],
        请选择: ['a-select', 'a-select-opt-group', 'a-date-picker', 'a-month-picker']
      } // 默认placeholder配置项
    }
  },
  watch: {
    // 监听form去添加选择人员的列表，请求详情映射form会改变form的this指向，所以只执行一次，除非form被重新覆盖改变指向
    form(e) {
      /**
       * 关于personKeys：类型为数组，用于人员列表的表单不是一个数组集合，而是一个id和name分离成单独的集合的的情况，数组第一个字符串是表单的《人员id的集合》的字段名，第二个字符串是表单的《人员name的集合》的字段名
       * eg：personKeys=['personIds','personNames'];表单：form={personIds:"1,2,3",personNames:"张三,李四,王五"}
       */
      for (let index in this.formList) {
        let item = this.formList[index]
        // 配置项人员字段personKeys存在，且表单项存在这两个字段；筛选出选择人员的表单配置项，并把id和name集合组合成list
        if (item.type === 'SelectPerson' && item.personKeys?.length >= 2 && e[item.personKeys[0]] && e[item.personKeys[1]]) {
          /**
           * 因为表单里的ids和names可能是个如:"1,2,3"的字符，若是字符则处理成数组过后再遍历
           */
          // ids集合
          let personIds = Array.isArray(e[item.personKeys[0]]) ? e[item.personKeys[0]] : e[item.personKeys[0]].split(',')
          // names集合
          let personNames = Array.isArray(e[item.personKeys[1]]) ? e[item.personKeys[1]] : e[item.personKeys[1]].split(',')
          // 添加人员列表到配置项，表单值为数组字符串，且两个表单分别为id集合和name集合，需要遍历合并为一个对象
          this.$set(
            this.personList,
            item.keyName,
            personIds.map((i, index) => ({
              [item.idField || 'userId']: i,
              name: personNames[index]
            }))
          )
        }
      }
    }
  },
  methods: {
    selectOrg(val) {
      // if(val&&val.length > 1) {
      //   const branchId = val[val.length - 2].orgId
      //   this.getAuditProjectList(branchId)
      // }
      this.$emit('selectOrg', val)
    },
    getProjectInfo(val) {
      this.$emit("getProjectInfo", val)
    },
    // 获取项目列表 目的只是为了查询项目编号
    getAuditProjectList(branchId) {
      const data = {
        branchComIds:[branchId]
      }
      getAuditProject(data)
              .then((res) => {
                if (res.code === 200) {
                  const project = res.data
                  this.$emit("getAuditProjectList", project)
                } else {
                  this.$message.error('err:', res.message)
                }
              })
              .catch((res) => {
                this.fetching = false
              })
    },
    /**
     * @description: 人员列表处理情况：1、人员列表的表单是个独立数组，则直接用表单值；2、人员列表的id和name分离成两个数组形成两个表单
     * @param {Object} item：表单配置对象
     */
    formatPerson(item) {
      let form = this.form
      let personList = form[item.keyName] // 人员的表单值
      let personIds = form?.[item.personKeys?.[0]] // 人员ids的表单值
      let personNames = form?.[item.personKeys?.[1]] // 人员names的表单值
      /**
       * 若表单配置项有personKeys数组（ids和names的字段名）且personKeys的第一个（ids的字段名）和第二个（names的字段名）都存在，则使用处理过的人员列表，否则说明人员列表的表单值本来就是带id和name完整的数组对象
       */
      return (item.personKeys?.length >= 2 && personIds && personNames ? this.personList[item.keyName] : personList) || []
    },
    /**
     * @description: 打开人员选择
     * @param {String} name
     */
    handleOpen(name) {
      this.$refs['dialogEdit' + name]?.[0].open()
    },
    /**
     * @description: 添加人员
     * @param {Array} t：人员列表
     * @param {Object} item：表单配置对象
     */
    handleAdd(t, item) {
      const personKeys = item.personKeys // 人员id和name的字段名
      let e = this.$clone(t) //人员列表
      let personList = item.isSingle ? [e] : e // 处理过的人员列表
      /**
       * 若表单配置项有personKeys数组（ids和names的字段名）且personKeys的第一个（ids的字段名）和第二个（names的字段名）都存在，则使用处理过的人员列表，否则说明人员列表的表单值本来就是带id和name完整的数组对象
       */
      if (personKeys && personKeys[0] && personKeys[1]) {
        // 添加人员集合
        this.personList[item.keyName] = personList
        // 添加id集合到表单
        this.$set(this.form, personKeys[0], item.isSingle ? e[item.idField || 'userId'] : e.map((i) => i[item.idField || 'userId'])?.join())
        // 添加name集合到表单
        this.$set(this.form, personKeys[1], item.isSingle ? e.name : e.map((i) => i.name)?.join())
      } else {
        this.$set(this.form, item.keyName, personList)
      }
      // 触发表单校验
      this.handleFileChange(item.keyName)
      // 父组件处理
      this.$emit('confirmSelect', personList)
      // 若是单选人员
      if (item.isSingle) {
        this.visible = false
      }
    },
    /**
     * @description:删除人员
     * @param {Number} index：索引值
     * @param {Object} item：表单配置对象
     */
    handleRemove(index, item) {
      const personKeys = item.personKeys
      let isSeparate = personKeys && personKeys[0] && personKeys[1] // 人员列表id和name表单是否需要用分离处理
      /**
       * 若表单配置项有personKeys数组（ids和names的字段名）且personKeys的第一个（ids的字段名）和第二个（names的字段名）都存在，则使用处理过的人员列表，否则说明人员列表的表单值本来就是带id和name完整的数组对象
       */
      if (isSeparate) {
        // 删除人员
        this.personList[item.keyName].splice(index, 1)
        // 删除ids集合里的id和names集合里的name
        personKeys?.forEach((item) => {
          let list = this.form[item]?.split(',')
          list.splice(index, 1)
          this.form[item] = list.join()
        })
      } else {
        this.form[item.keyName].splice(index, 1)
      }
      // 触发表单校验
      this.handleFileChange(item.keyName)
      // 父组件处理
      this.$emit('handleRemove', isSeparate ? this.personList[item.keyName] : this.form[item.keyName])
    },
    /**
     * @description: 触发表单校验
     * @param {String} name：附件字段名
     * @return {*}
     */
    handleFileChange(name) {
      if (this.editModel != 'V') {
        this.$nextTick(() => {
          // 若是组件内表单
          if (this.$parent.$parent.isValidate) {
            this.$parent.$parent.$refs.ruleForm?.validateField(name)
          } else {
            this.formComponents?.[this.formName]?.validateField(name)
          }
        })
      }
    },
    /**
     * @description: 日期选择面板改变
     * @param {String} keyName：字段名
     * @param {String} value：值
     */
    panelChange(keyName, value) {
      this.$set(this.form, keyName, value)
    },
    /**
     * @description: 获取placeholder
     * @param {Object} item：表单配置对象
     * @return {String}
     */
    getPlaceholder(item) {
      // 遍历默认项，筛选出对应placeholder
      for (let index in this.defaultPlaceholder) {
        if (this.defaultPlaceholder[index].includes(item.type)) {
          return index + item.label
        }
      }
      return void 0
    },
    /**
     * @description: 动态绑定输入限制值
     * @param {Object} i：表单配置对象
     * @return {Object}
     */
    getAttrs(i) {
      let attrs = i.attrs || {}
      if (i?.type === 'a-input' || i?.type === 'a-textarea') {
        attrs.maxLength = { 'a-input': attrs?.type === 'textarea' ? 300 : 30, 'a-textarea': 300 }[i.type]
      }
      if(!attrs.treeNodeFilterProp) {
        attrs.treeNodeFilterProp = 'title'
      }
      return attrs
    },
    /**
     * @description: 动态绑定表单校验项
     * @param {Object} i：表单配置对象
     * @return {Object}
     */
    getProp(i) {
      let attrs = {}
      if (this.editModel !== 'V' && !i.disabled) {
        attrs.prop = i.keyName
      }
      return attrs
    },
    /**
     * @description: 预处理事件回调
     * @param {Object} e：表单配置对象
     * @return {Object}
     */
    listeners(e) {
      let that = this
      let name = e.keyName
      const $listeners = {}
      // 若使用自定义事件，则基于事件绑定标识name，标识为每个表单的键名，防止多个表单同个事件无法分别做回调
      if (that.isEmit) {
        // 遍历事件绑定name
        for (let index in that.$listeners) {
          // 过滤双向绑定事件
          if (index.indexOf('update:') == -1) {
            $listeners[index] = function () {
              that.$emit(index, name, ...arguments)
            }
          }
        }
      } else {
        /**
         * 不使用自定义事件，则在formList配置项里直接回调
         * eg:{
              keyName: 'time',
              type: 'a-date-picker',
              label: '时间',
              attrs: {
                valueFormat: 'YYYY-MM-DD',
              },
              change(){
                console.log(arguments)
              }
            },
         */
        for (let idx in e) {
          // 过滤非函数和转义函数
          if (e[idx] instanceof Function && idx != 'customRenderLabel' && idx != 'customRender') {
            $listeners[idx] = e[idx]
          }
        }
      }
      // console.log($listeners)
      return Object.assign({}, $listeners)
    },
    /**
 * @description:获取当前选中的岗位数据
 */
    getPostInfo(data){
      this.$emit("getPostInfo", data)
    }
  }
}
</script>
<style scoped>
.text_name {
  margin-top: -3px;
  display: block;
  word-wrap: break-word;
  word-break: break-all;
}

.file_prompt {
  color: #999;
}
</style>
